/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_SDdriver.h"
#include <string.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, 0xFFFF);
    return ch;
}

FATFS fs_obj;
FATFS *pFs_obj = &fs_obj;
FIL fil_obj;
FIL *pFil_obj = &fil_obj;
uint8_t FatFsReadBuff[512] = {0};

const char strPath[] = "0:TestDocument.txt";


FRESULT SD_Fs_ScanfFile(uint8_t *path)
{
    FRESULT res;
    DIR dir_var;
    FILINFO fileInfo_var;
    uint32_t CountOut = 0xFFFFFFFF;

    res = f_opendir(&dir_var, (const TCHAR *)path);

    if (res == FR_OK)
    {
        while (CountOut--)
        {
            res = f_readdir(&dir_var, &fileInfo_var);
            if ((res != FR_OK) || (fileInfo_var.fname[0] == 0))
            {
                break;
            }
            printf("%s/", path);
            printf("%s. \r\n", fileInfo_var.fname);
        }
    }
    f_closedir(&dir_var);

    return res;
}

HAL_StatusTypeDef SD_Fs_Test(void)
{
    FRESULT fsResult;
    uint32_t fileSize = 0, readCount = 0, writeCount = 0;

    /* 1. Mount device */
    fsResult = f_mount(pFs_obj, "0:", 1);
    if (fsResult == 0)
    {
        printf("Successfully mount! \r\n");
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }

    fsResult = SD_Fs_ScanfFile("0:");
    if (fsResult == FR_OK)
    {
        printf("Successfully scanf path! \r\n");
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }


    /* 2. Open file */
    fsResult = f_open(pFil_obj, "0:testA123.txt", FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
    // fsResult = f_open(pFil_obj, "0:aa22BB.txt", FA_READ | FA_WRITE);
    if (fsResult == 0)
    {
        printf("Successfully open file! \r\n");
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }

    /* 3. Read data */
    fileSize = f_size(pFil_obj);
    fsResult = f_read(pFil_obj, FatFsReadBuff, fileSize, &readCount);
    if (fsResult == 0)
    {
        printf("Successfully read file! \r\n");
        printf("readCount: %d. \r\n", readCount);
        if (readCount != 0)
        {
            printf("------------------------------------------> Data: <------------------------------------------ \r\n");
            printf("%s \r\n", FatFsReadBuff);
            printf("------------------------------------------> Data END <------------------------------------------ \r\n");
            printf("\r\n");
        }
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }

    /* 4. Write data */
    // const uint8_t WriteData[] = "MCU write: Hello! I'm MCU. \r\n";
    const uint8_t WriteData[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x08, '0', '0', '1'};
    fsResult = f_write(pFil_obj, WriteData, sizeof(WriteData), &writeCount);
    if (fsResult == 0)
    {
        printf("Successfully write file! \r\n");
        printf("writeCount: %d. \r\n", readCount);

        memset(FatFsReadBuff, 0, sizeof(FatFsReadBuff));
        f_lseek(pFil_obj, 0);
        fileSize = f_size(pFil_obj);
        fsResult = f_read(pFil_obj, FatFsReadBuff, fileSize, &readCount);
        if (fsResult == 0)
        {
            printf("Successfully read file! \r\n");
            printf("readCount: %d. \r\n", readCount);
            if (readCount != 0)
            {
                printf("------------------------------------------> Data: <------------------------------------------ \r\n");
                uint32_t i = 0;
                for (i = 0; i < readCount; i++)
                {
                    printf("%02X ", FatFsReadBuff[i]);
                }
                printf("\r\n");
                printf("------------------------------------------> Data END <------------------------------------------ \r\n");
            }
        }
        else
        {
            printf("Error! fsResult: %d \r\n", fsResult);
        }
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }

    /* END. close file */
    fsResult = f_close(pFil_obj);
    if (fsResult == 0)
    {
        printf("Successfully close file! \r\n");
    }
    else
    {
        printf("Error! fsResult: %d \r\n", fsResult);
    }

    return HAL_OK;
}

uint8_t SD_WriteBuff[512 * 3] = {0};
uint8_t SD_ReadBuff[512 * 3] = {0};

HAL_StatusTypeDef SD_Card_Init(void)
{
    HAL_StatusTypeDef result = HAL_ERROR;

    result = Bsp_SD_Init(); // SD卡初始化
    printf("\r\n");
    if (result == HAL_OK)
    {
        printf("SD card initialization successful! \r\n");
    }
    else
    {
        printf("SD card initialization failed! \r\n");
        return HAL_ERROR;
    }

    if (Bsp_SD_GetCardInfo(&Bsp_SDCardInfo) == HAL_OK)
    {
        printf("Successfully read CID! \r\n");
    }
    else
    {
        printf("Failed to read CID! \r\n");
        return HAL_ERROR;
    }

    printf("result: %d \r\n", result);
    printf("------------------------ SD Information ------------------------\r\n");
    if (Bsp_SDCardInfo.Capacity > (1024 * 1024 * 1024))
    {
        printf("Capacity: %dGb. \r\n", Bsp_SDCardInfo.Capacity / (1024 * 1024 * 1024));
    }
    else if (Bsp_SDCardInfo.Capacity > (1024 * 1024))
    {
        printf("Capacity: %dMb. \r\n", Bsp_SDCardInfo.Capacity / (1024 * 1024));
    }
    else if (Bsp_SDCardInfo.Capacity > (1024))
    {
        printf("Capacity: %dKb. \r\n", Bsp_SDCardInfo.Capacity / (1024));
    }
    else
    {
        printf("Capacity: %dByte. \r\n", Bsp_SDCardInfo.Capacity);
    }
    printf("BlockSize: %d \r\n", Bsp_SDCardInfo.BlockSize);
    printf("RCA: %d \r\n", Bsp_SDCardInfo.RCA);
    printf("CardType: %d \r\n", Bsp_SDCardInfo.CardType);
    printf("SpaceTotal: %d \r\n", Bsp_SDCardInfo.SpaceTotal);
    printf("SpaceFree: %d \r\n", Bsp_SDCardInfo.SpaceFree);

    // printf("------------------------ CID: ------------------------\r\n");
    // printf("ManufacturerID: %d \r\n", Bsp_SDCardInfo.CID.ManufacturerID);
    // printf("OEM_AppliID: %d \r\n", Bsp_SDCardInfo.CID.OEM_AppliID);
    // printf("ProdName1: %d \r\n", Bsp_SDCardInfo.CID.ProdName1);
    // printf("ProdName2: %d \r\n", Bsp_SDCardInfo.CID.ProdName2);
    // printf("ProdRev: %d \r\n", Bsp_SDCardInfo.CID.ProdRev);
    // printf("ProdSN: %d \r\n", Bsp_SDCardInfo.CID.ProdSN);
    // printf("Reserved1: %d \r\n", Bsp_SDCardInfo.CID.Reserved1);
    // printf("ManufactDate: %d \r\n", Bsp_SDCardInfo.CID.ManufactDate);
    // printf("CID_CRC: %d \r\n", Bsp_SDCardInfo.CID.CID_CRC);
    // printf("Reserved2: %d \r\n", Bsp_SDCardInfo.CID.Reserved2);
    printf("\r\n");

#if 0
    if (Bsp_SD_ReadDisk(SD_ReadBuff, 0, 3) == HAL_OK)
    {
        printf("Successfully read buff! \r\n");
        printf("Buff: \r\n");
        for (i = 0; i < sizeof(SD_ReadBuff); i += 4)
        {
            if ((i % 32) == 0)
            {
                printf("\r\n");
            }
            if ((i % 512) == 0)
            {
                printf("\r\n-------------*---------------\r\n");
            }
            printf("0x%02X%02X%02X%02X ", SD_ReadBuff[i], SD_ReadBuff[i + 1], SD_ReadBuff[i + 2], SD_ReadBuff[i + 3]);
        }
        printf("\r\n");
    }
    else
    {
        printf("Failed to read buff! \r\n");
        return HAL_ERROR;
    }
#elif 0

    for (i = 0; i < sizeof(SD_WriteBuff); i++)
    {
        SD_WriteBuff[i] = (i * 4) & 0xFF;
    }
    if (Bsp_SD_WriteDisk(SD_WriteBuff, 1, 2) == HAL_OK)
    {
        printf("Successfully Write buff! \r\n");
    }
    else
    {
        printf("Failed to Write buff! \r\n");
        return HAL_ERROR;
    }
#endif

    return HAL_OK;
}

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_SPI3_Init();
    MX_USART1_UART_Init();
    MX_FATFS_Init();
    /* USER CODE BEGIN 2 */
    // Get_SDCard_Capacity();
    HAL_Delay(1000);
    SD_Card_Init();
    SD_Fs_Test();

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    printf("TF model init. \r\n");
    while (1)
    {
        printf(".");
        HAL_Delay(1000);
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 25;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  Period elapsed callback in non blocking mode
 * @note   This function is called  when TIM2 interrupt took place, inside
 * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
 * a global variable "uwTick" used as application time base.
 * @param  htim : TIM handle
 * @retval None
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    /* USER CODE BEGIN Callback 0 */

    /* USER CODE END Callback 0 */
    if (htim->Instance == TIM2)
    {
        HAL_IncTick();
    }
    /* USER CODE BEGIN Callback 1 */

    /* USER CODE END Callback 1 */
}

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
